package cn.dansj.service.Impl;

import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.StringUtils;
import cn.dansj.entity.InterfaceGroup;
import cn.dansj.entity.InterfaceInfo;
import cn.dansj.repository.InterfaceInfoRepository;
import cn.dansj.service.InterfaceInfoService;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.Verification;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.criteria.Predicate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

@Service
public class InterfaceInfoServiceImpl implements InterfaceInfoService {
    private final InterfaceInfoRepository interfaceInfoRepository;

    public InterfaceInfoServiceImpl(InterfaceInfoRepository interfaceInfoRepository) {
        this.interfaceInfoRepository = interfaceInfoRepository;
    }

    @Override
    public Page<InterfaceInfo> searchInterface(Integer pageNum, Integer pageLimit, String interfaceName, String url, String status, String method, String type, String apiType, String group) {
        Sort sort = Sort.by(Sort.Direction.DESC, "crtTime");
        Pageable pageable = PageRequest.of(pageNum - 1, pageLimit, sort);
        Specification<InterfaceInfo> specification = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> paramsList = new ArrayList<>();
            if (Verification.checkNotNull(url)) {
                paramsList.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("url")), url.toLowerCase()));
            }

            if (Verification.checkNotNull(status)) {
                paramsList.add(criteriaBuilder.equal(root.get("status"), Transformation.parseInt(status)));
            }

            if (Verification.checkNotNull(apiType)) {
                paramsList.add(criteriaBuilder.equal(root.get("apiType"), Transformation.parseInt(apiType)));
            }

            if (Verification.checkNotNull(method)) {
                paramsList.add(criteriaBuilder.equal(root.get("method"), method));
            }

            if (Verification.checkNotNull(group)) {
                Subquery<Integer> subQuery = criteriaQuery.subquery(Integer.class);
                Root<InterfaceGroup> subRoot = subQuery.from(InterfaceGroup.class);
                subQuery.select(criteriaBuilder.literal(1)).where(criteriaBuilder.equal(subRoot.get("interfaceSequence"), root.get("sequence")), criteriaBuilder.equal(subRoot.get("inGroup"), group));
                paramsList.add(criteriaBuilder.exists(subQuery));
            }

            if (Verification.checkNotNull(type)) {
                paramsList.add(criteriaBuilder.equal(root.get("type"), type));
            }

            if (Verification.checkNotNull(interfaceName)) {
                paramsList.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("interfaceName")), interfaceName.toLowerCase()));
            }

            Predicate[] predicates = new Predicate[paramsList.size()];
            return criteriaBuilder.and(paramsList.toArray(predicates));
        };
        return interfaceInfoRepository.findAll(specification, pageable);
    }

    @Override
    public InterfaceInfo getInterface(String url, int status, String method) {
        return interfaceInfoRepository.getInterfaceInfoByUrlAndStatusAndMethod(url, status, method);
    }

    @Override
    public InterfaceInfo getBySequence(String sequence) {
        return interfaceInfoRepository.getBySequence(sequence);
    }

    @Override
    public InterfaceInfo getByName(String name) {
        return interfaceInfoRepository.getByInterfaceName(name);
    }

    @Override
    public boolean checkInterfaceUrl(String sequence, String url) {
        long cnt = interfaceInfoRepository.checkInterfaceUrl(sequence, url);
        return cnt != 0;
    }

    @Override
    public boolean checkInterfaceName(String sequence, String name) {
        return interfaceInfoRepository.checkInterfaceName(sequence, name) != 0;
    }

    @Override
    public void save(InterfaceInfo interfaceInfo) {
        interfaceInfoRepository.save(interfaceInfo);
    }

    @Override
    public List<InterfaceInfo> save(List<InterfaceInfo> interfaceInfoList) {
        return interfaceInfoRepository.saveAll(interfaceInfoList);
    }

    @Override
    @Transactional
    public void updateStatus(String sequence, Integer status) {
        interfaceInfoRepository.updateStatus(sequence, status);
    }

    @Override
    public int getTotalNum() {
        return interfaceInfoRepository.countAll();
    }

    @Override
    public List<InterfaceInfo> getAllInterface() {
        return interfaceInfoRepository.getAllInterface();
    }

    @Override
    public long countForeignInterface() {
        return interfaceInfoRepository.countForeignInterface();
    }

    @Override
    @Transactional
    public int deleteBySequence(String sequence) {
        return interfaceInfoRepository.deleteBySequence(sequence);
    }

    @Override
    public List<String> getAuthList() {
        return interfaceInfoRepository.getAuthList().stream().flatMap(e ->
                ArrayUtils.asList(e).stream().filter(Verification::checkNotNull).flatMap(l -> Arrays.stream(StringUtils.split(l, ",")))
        ).distinct().toList();
    }
}
